<template>
  <div class="qm-table">
    <!-- 查询按钮和重置 -->
    <template>
      <el-form :inline="inline" :model="model" ref="searchForm">
        <slot name="input"></slot>
        <el-form-item v-if="showqueryreset">
          <el-button type="primary" @click="fetchListData(null, model)"
            >查询</el-button
          >
          <el-button
            type="info"
            @click="
              $emit('update:model', {});
              datas = {};
              fetchListData();
            "
            >重置</el-button
          >
        </el-form-item>
      </el-form>
    </template>
    <!-- 左上角新增按钮 -->
    <vxe-toolbar v-if="showToolbar" v-bind="finalToolbarOptions">
      <template v-slot:buttons>
        <el-button
          icon="el-icon-circle-plus-outline"
          v-if="finalShowAdd"
          @click="addNew"
          type="primary"
          size="small"
        >
          {{ textMap.add || "新增" }}
        </el-button>
        <el-button
          icon="el-icon-download"
          v-if="showExport"
          @click="excelExport('.xlsx')"
          type="primary"
          size="small"
        >
          {{ textMap.export || "导出Excel" }}
        </el-button>
        <el-button
          icon="el-icon-download"
          v-if="showSeniorExport"
          @click="seniorExport"
          type="primary"
          size="small"
        >
          {{ textMap.seniorExport || "高级导出" }}
        </el-button>
        <el-button
          icon="el-icon-remove-outline"
          v-if="showCheckbox && finalShowDelete"
          type="danger"
          @click="deleteSelected"
          size="small"
        >
          {{ textMap.delSelected || "删除" }}
        </el-button>
        <slot name="toolbar"></slot>
      </template>
    </vxe-toolbar>
    <!-- 列表 -->
    <vxe-table
      v-bind="finalOptions"
      v-on="finalTableEvents"
      ref="xTable"
      :data="data.data"
      :loading="tableLoading"
      @sort-change="sortChange"
      class="qm-table-vxe-table"
    >
      <vxe-column
        v-if="showRadio"
        type="radio"
        width="60"
        align="center"
        fixed="left"
      >
        <template #header>
          <el-button
            type="text"
            @click="$refs.xTable.clearRadioRow()"
            style="color: #606266"
            >取消</el-button
          >
        </template>
      </vxe-column>
      <vxe-column
        v-if="showCheckbox"
        align="center"
        type="checkbox"
        width="60"
        fixed="left"
      ></vxe-column>

      <vxe-column
        v-if="showOrder"
        type="seq"
        align="center"
        :title="textMap.order || '序号'"
        width="60"
        fixed="left"
      ></vxe-column>
      <slot></slot>

      <vxe-column v-if="showMenu" v-bind="finalMenuOptions">
        <template v-slot="{ row }">
          <template v-if="menuType === 'icon'">
            <el-button
              v-if="
                finalShowView &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.view(row)
              "
              icon="el-icon-view"
              circle
              @click="viewInfo(row)"
            ></el-button>
            <el-button
              v-if="
                finalShowEdit &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.edit(row)
              "
              type="primary"
              icon="el-icon-edit"
              circle
              @click="showEditModal(row)"
            ></el-button>
            <el-button
              v-if="
                finalShowDelete &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.remove(row)
              "
              type="danger"
              icon="el-icon-delete"
              circle
              @click="remove(row)"
            ></el-button>
          </template>
          <template v-else-if="menuType === 'text'">
            <el-button
              type="text"
              v-if="
                finalShowView &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.view(row)
              "
              @click="viewInfo(row)"
              >{{ textMap.view || "查看" }}</el-button
            >
            <el-button
              type="text"
              v-if="
                finalShowEdit &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.edit(row)
              "
              @click="showEditModal(row)"
              >{{ textMap.edit || "编辑" }}</el-button
            >
            <el-button
              type="text"
              v-if="
                finalShowDelete &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.remove(row)
              "
              @click="remove(row)"
              >{{ textMap.remove || "删除" }}</el-button
            >
          </template>
          <template v-else>
            <el-button
              v-if="
                finalShowView &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.view(row)
              "
              icon="el-icon-view"
              type="text"
              @click="viewInfo(row)"
              >{{ textMap.view || "查看" }}</el-button
            >
            <el-button
              v-if="
                finalShowEdit &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.edit(row)
              "
              icon="el-icon-edit"
              type="text"
              @click="showEditModal(row)"
              >{{ textMap.edit || "编辑" }}</el-button
            >
            <el-button
              v-if="
                finalShowDelete &&
                hasKeyValue(row) &&
                finalOperMenuRenderFuncMap.remove(row)
              "
              icon="el-icon-delete"
              type="text"
              @click="remove(row)"
              >{{ textMap.remove || "删除" }}</el-button
            >
          </template>
          <slot name="moreBtn" v-bind:row="row"></slot>
        </template>
      </vxe-column>
    </vxe-table>
    <!-- 分页 -->
    <template v-if="showPager">
      <el-pagination
        v-if="elPager"
        class="qm-table-el-pager"
        @size-change="handleElPageSizeChange"
        @current-change="handleElPageChange"
        :current-page="data.startIndex"
        v-bind="finalPagerOptions"
        :page-size="data.pageSize"
        :total="data.recordsTotal"
      ></el-pagination>

      <vxe-pager
        v-else
        :current-page="data.startIndex"
        :page-size="data.pageSize"
        :total="data.recordsTotal"
        v-bind="finalPagerOptions"
        @page-change="handlePageChange"
      ></vxe-pager>
    </template>
    <!-- 高级导出模态框 -->
    <qm-export-modal
      v-if="showSeniorExport"
      v-model="exportModalVisible"
      @export-modal-close="exportModalVisible = false"
      :exportConfig="finalExportConfig"
      :seniorExportUrl="seniorExportUrl"
      :modalOptions="finalExportModalOptions"
    >
    </qm-export-modal>
  </div>
</template>

<script>
import _ from "lodash";
import { checkPermi } from "@/utils/permission";
import request from "@/utils/request";
import QmExportModal from "@/libs/components/qm-export-modal";

import Vue from "vue";
import BaseModel from "@/libs/models/BaseModel.js";
import ListModel from "@/libs/models/ListModel.js";
import Util from "../framework/util";
// import Services from "./services";
import LoaderProxy from "../framework/loaderProxy";
import qs from "qs";
import { mountManualTriggerGuide, loadAutoTriggerGuide } from "@/utils/guide";
import QmForm from "@/libs/components/qm-form.vue";

export default {
  components: {
    QmExportModal,
    QmForm,
  },
  props: {
        // 传递过来的urls
    urls: {
      type: Object,
      default: () => {},
    },
    // 传递过来需要查询的值
    model: {
      type: Object,
      default: () => {},
    },
    // 是否启用行内表单模式
    inline: {
      type: Boolean,
      default: true,
    },
    // 是否显示查询和重置按钮
    showqueryreset: {
      type: Boolean,
      default: true,
    },
    // 是否显示导出Excel按钮
    showExport: {
      type: Boolean,
      default: false,
    },
    // 指定的新增页、编辑页和查看页，不指定将统一用 create.vue 来作为表单页
    formPage: {
      type: Object,
      default: () => {
        return {
          // 参考示例
          // create: '/admin/sysUser/create',
          // edit: '/admin/sysUser/create',
          // view: '/admin/sysUser/create'
        };
      },
    },
    // 获取实体之前，带三个参数：params, row, pageAction
    // row 表示列表的一条记录
    // beforeGetEntity: {
    //   type: Function,
    // },
    /**
     * 操作菜单渲染方法：
     */
    operMenuRenderFuncMap: {
      type: Object,
      default: () => {
        return {
          remove: (row) => true,
          edit: (row) => true,
          view: (row) => true,
        };
      },
    },
    // 主键属性，指该列表对应的实体的主键属性，如：userId，typeId等，请尽量指定主键属性
    // 双主键请用英文逗号分隔，如：userId,profileId
    keyProp: {
      type: String,
    },
    // 是否使用指定的页面来作为表单页
    useFormPage: {
      type: Boolean,
      default: false,
    },
    // 是否显示操作列查看按钮
    showView: {
      type: Boolean,
      default: true,
    },
    // 是否显示序号
    showOrder: {
      type: Boolean,
      default: true,
    },
    // 是否显示分页
    showPager: {
      type: Boolean,
      default: true,
    },
    // 操作列类型，纯图标 icon，纯文本 text，文本图标 icontext
    menuType: {
      type: String,
      default: "icon",
    },
    // 是否显示高级导出按钮
    showSeniorExport: {
      type: Boolean,
      default: false,
    },
    // 是否显示操作列
    showMenu: {
      type: Boolean,
      default: true,
    },
    // 是否显示复选框
    showCheckbox: {
      type: Boolean,
      default: true,
    },
    // 是否显示工具栏
    showToolbar: {
      type: Boolean,
      default: true,
    },
    // 是否显示新增按钮
    showAdd: {
      type: Boolean,
      default: true,
    },
    // 是否显示操作列编辑按钮
    showEdit: {
      type: Boolean,
      default: true,
    },
    // 是否显示单选框
    showRadio: {
      type: Boolean,
      default: false,
    },
    // 是否显示操作列删除按钮
    showDelete: {
      type: Boolean,
      default: true,
    },
    // 请求之前，带一个参数：params，仅对于指定urls的实例有效
    beforeQuery: {
      type: Function,
    },
    // 请求之后，带两个参数：isSuccess、result，仅对于指定urls的实例有效
    afterQuery: {
      type: Function,
    },
    // 列表刷新的方法实现，将会覆盖默认的列表刷新方法，接收一个参数params，一些请求参数
    refreshFunc: {
      type: Function,
    },
    // 删除按钮的方法实现，将会覆盖默认的删除方法实现，接收一个参数rows，表示选中的行，
    // 如果是点击操作列的删除按钮，则rows只有一个元素
    removeFunc: {
      type: Function,
    },
    // 列表刷新类型，取值list、list$1、list$2 等，与controller的this.urls.query的类型对应
    // 值为 none 表示不刷新
    refreshType: {
      type: String,
      default: "list",
    },
    // 列表显示的数据，取值为后台的分页对象PagerInfo，即列表页的query属性
    // 编辑按钮的方法实现，将会覆盖默认的编辑方法实现，接收一个参数row，表示当前行
    editFunc: {
      type: Function,
    },
    data: {
      type: Object,
      default: () => {
        return {
          data: [],
          draw: 1,
          startIndex: 1,
          pageSize: 10,
          pages: 1,
          recordsFiltered: 10,
          recordsTotal: 10,
        };
      },
    },
    // 一些按钮的默认文字
    textMap: {
      type: Object,
      default: () => {
        return {
          add: "新增",
          view: "查看",
          edit: "编辑",
          remove: "删除",
          delSelected: "删除",
          export: "导出Excel",
          seniorExport: "高级导出",
          order: "序号",
          save: "保 存",
          cancel: "取 消",
        };
      },
    },
    // 表格的一些事件配置，请参考vxe-table 3.x版本文档：https://xuliangzhan_admin.gitee.io/vxe-table/#/table/api
    tableEvents: {
      type: Object,
      default: () => {},
    },
    // 操作列的一些属性配置，请参考vxe-table 3.x版本文档：https://xuliangzhan_admin.gitee.io/vxe-table/#/table-column/api
    menuOptions: {
      type: Object,
      default: () => {},
    },
    // 工具栏的一些属性配置，请参考vxe-table 3.x版本文档：https://xuliangzhan_admin.gitee.io/vxe-table/#/toolbar/api
    toolbarOptions: {
      type: Object,
      default: () => {},
    },
    // 分页行的一些属性配置，请参考vxe-table 3.x版本文档：https://xuliangzhan_admin.gitee.io/vxe-table/#/pager/api
    pagerOptions: {
      type: Object,
      default: () => {},
    },
    /**
     * 是否启用el-pagination的分页组件，默认true，false 表示使用vxe-pager
     *
     * 注：嵌套的 el-dialog 或 vxe-modal 里面存在 vxe-pager 时，点击分页按钮可能会出现页面跳转(刷新)的问题。
     * 出现此问题，请检查vxe-pager组件是否内嵌于form表单内，如果是，只需要移出form表单即可。
     *
     * 原因：vxe-pager被el-form(form表单)包裹时，点击分页按钮会触发表单的action属性，从而导致页面跳转(刷新)的问题。
     */
    elPager: {
      type: Boolean,
      default: true,
    },
    // 是否显示进入页面时的加载中图标
    showLoading() {
      return true;
    },
    // 高级导出的配置
    exportConfig: {
      type: Object,
      default: () => {
        return {
          /**
          参考示例：
            filename：文件名，默认为"导出_20210915150452"，
            type：文件类型，默认为"xlsx"(暂时只支持xlsx)
            columns: 选择字段，必须。[{
              field: xxx,
              title: xxx
            }]
           */
        };
      },
    },
    // 高级导出接口地址
    seniorExportUrl: {
      type: String,
      required: false,
    },
    // 导出模态框属性配置，请参考vxe-table 3.x版本文档：https://xuliangzhan_admin.gitee.io/vxe-table/#/modal/api
    exportModalOptions: {
      type: Object,
      default: () => {},
    },
    // 是否自动触发加载完成事件
    autoLoadDone() {
      return true;
    },
  },
  data() {
    return {
      formModalVisible: false,
      formModalLoading: false,
      viewModel: {
        search: { arg2: "系统管理员" },
        controlData: {},
        models: {
          model: {},
        },
        defaults: {},
        enums: {},
        initMessage: null,
      },
      primaryKey: {},
      tableLoading: false,
      saveLoading: false,
      formDisabled: true,
      formPath: "",
      exportModalVisible: false,
      exportColumns: [],
      loaders: [],
      permissions: {},
      context: {},
      res: {
        deleteConfirm: "确定要删除选择的记录吗？",
        deleteError: "删除失败！",
        deleteSuccess: "删除成功！",
        noSelectAtDeleting: "请先选择要删除的记录。",
        createError: "创建失败！",
        createSuccess: "创建成功！",
        updateError: "更新失败！",
        updateSuccess: "更新成功！",
      },
      pageAction: "",
      autoMountManualTriggerGuide: false,
      listOptions: {
        searchKey: "allInLike",
      },
      $util: {},
      vm: {},
      datas: {},
    };
  },
  watch: {
    urls(n, o) {
      if (!this.isRemoteList) {
        return;
      }
      let q1 = (n || {}).query;
      let q2 = (o || {}).query;
      if (!q1 || q1 === q2) {
        return;
      }
      this.fetchListData();
    },
  },
  computed: {
    finalToolbarOptions() {
      return _.extend({}, this.toolbarOptions);
    },
    // ———————————————————————————————————————————————————————————————————
    // 用来判定传输过来的this.urls和this.urls.query是不是空的对象。
    isRemoteList() {
      // isEmpty用来判定是否为一个空对象，集合，映射或set如果是空返回true，否则false

      return !(_.isEmpty(this.urls) || _.isEmpty(this.urls.query));
    },
    finalShowAdd() {
      if (this.isRemoteList) {
        return this.showAdd && this.keyProp && this.urls.entity;
      }
      return (
        this.showAdd &&
        this.keyProp &&
        this.permissionCheck(this.getPermission("add"))
      );
    },
    finalOptions() {
      return _.extend(
        {
          border: true,
          highlightHoverRow: true,
          highlightHoverColumn: true,
          autoResize: true,
          checkboxConfig: { highlight: true },
          sortConfig: {
            remote: true,
            trigger: "cell",
            orders: ["asc", "desc", null],
          },
        },
        this.options
      );
    },
    finalTableEvents() {
      return _.extend({}, this.tableEvents);
    },
    finalMenuOptions() {
      return _.extend(
        {
          title: "操作",
          width: 150,
          fixed: "right",
        },
        this.menuOptions
      );
    },
    finalPagerOptions() {
      if (this.elPager) {
        return _.extend(
          {
            layout: "total, sizes, prev, pager, next, jumper",
            pageSizes: [5, 10, 20, 50, 100],
          },
          this.pagerOptions
        );
      }
      return _.extend(
        {
          layouts: [
            "Total",
            "Sizes",
            "PrevJump",
            "PrevPage",
            "JumpNumber",
            "NextPage",
            "NextJump",
            "FullJump",
          ],
          pageSizes: [5, 10, 20, 50, 100],
        },
        this.pagerOptions
      );
    },
    finalExportConfig() {
      return _.extend({}, { columns: this.exportColumns }, this.exportConfig);
    },
    finalShowView() {
      if (this.isRemoteList) {
        return this.showView && this.keyProp && this.urls.entity;
      }
      return (
        this.showView &&
        this.keyProp &&
        this.permissionCheck(this.getPermission("view"))
      );
    },
    finalOperMenuRenderFuncMap() {
      return _.extend(
        {
          remove: (row) => true,
          edit: (row) => true,
          view: (row) => true,
        },
        this.operMenuRenderFuncMap
      );
    },
    finalShowDelete() {
      if (this.isRemoteList) {
        return (
          this.showDelete &&
          this.keyProp &&
          (this.urls.delete || this.urls.remove)
        );
      }
      return (
        this.showDelete &&
        this.keyProp &&
        this.permissionCheck(this.getPermission("delete"))
      );
    },
    finalExportModalOptions() {
      return _.extend({}, this.exportModalOptions);
    },
    finalShowEdit() {
      if (this.isRemoteList) {
        return this.showEdit && this.keyProp && this.urls.entity;
      }
      return (
        this.showEdit &&
        this.keyProp &&
        this.permissionCheck(this.getPermission("edit"))
      );
    },
  },
  methods: {
    // 搜索
    searchQuery(value, type) {
      if (Util.isString(value)) {
        this.setSearch(this.listOptions.searchKey, value, type);
      } else {
        if (value instanceof MouseEvent) {
          value = {};
        }
        value = value || {};
        if (!Util.isEmpty(value)) {
          value = {
            query: value,
          };
        }
      }
      let $table = this.$refs["xTable"];
      if ($table) {
        $table.tableLoading = true;
      }
      this.getLoader(type)
        .query(Util.isString(value) ? {} : value)
        .then(
          (values) => {
            this.bind(values);
            if ($table) {
              $table.clearSort();
              $table.tableLoading = false;
            }
          },
          (values) => {
            if ($table) {
              $table.tableLoading = false;
            }
            this.msgError("请求失败，请稍候再试");
            console.error(values);
          }
        );
    },
    /**
     * 设置查询条件，仅适用于列表请求
     * @param {*} key 参数名
     * @param {*} value 参数值
     * @param {*} type 列表类型，list, list$1, list$2 等
     */
    setSearch(key, value, type) {
      var sKey = "search";
      if (type) {
        sKey += type.replace("list", "");
      }
      if (this.context[sKey] == undefined) {
        this.context[sKey] = {};
      }
      var inst = this.context[sKey];
      if (Util.isString(value)) {
        value = Util.toString(value);
      }
      inst[key] = value;
    },

    getFormPage() {
      if (!this.useFormPage) {
        return {};
      }
      if (_.isEmpty(this.formPage)) {
        let urls = this.urls;
        return urls && urls.create
          ? { create: urls.create, edit: urls.create, view: urls.create }
          : {};
      }
      return this.formPage;
    },
    computePage(pageAction) {
      let vpath = this.getFormPage()[pageAction];
      return (resolve) => require(["@/views" + vpath], resolve);
    },

    getPrimaryKey(keys, row) {
      let o = {};
      _.each(keys.split(","), (key) => {
        let k = key.trim();
        o[k] = row[k];
      });
      return o;
    },
    getPermission(key) {
      return this.permissions[key] || "";
    },
    hasKeyValue(row) {
      let hasValue = true;
      _.each(this.keyProp.split(","), (key) => {
        let k = key.trim();
        if (!row[k]) {
          hasValue = false;
        }
      });
      return hasValue;
    },
    // enablePermission ===是否启用权限控制
    permissionCheck(value) {
      if (!this.enablePermission || !value) {
        return true;
      }
      return checkPermi(_.isArray(value) ? value : [value]);
    },
    // 当排序触发的时候会执行以下事件
    sortChange({ column, property, order }) {
      let params = {};
      if (order) {
        params = {
          order: {
            field: property,
            dir: order ? order : "",
          },
        };
      }
      this.refresh(params);
    },
    refresh(params = {}) {
      params = _.extend(
        {},
        {
          start: (this.data.startIndex - 1) * this.data.pageSize,
          length: this.data.pageSize,
        },
        params
      );
      if (this.refreshFunc) {
        return this.refreshFunc(params);
      }
      if (this.isRemoteList) {
        this.fetchListData(params, {});
      } else {
        if (this.refreshType && this.refreshType !== "none") {
          this.tableLoading = true;
          this.fetchData(params, this.refreshType, false).then((r) => {
            this.tableLoading = false;
          });
        }
      }
    },
    //#region 列表
    getLoader(type = "list") {
      return this.loaders[type];
    },
    setLoader(loader) {
      this.loaders[loader.getType()] = loader;
    },

    fetchListData(otherParams = {}, data = {}) {
      if (!this.isRemoteList) {
        return;
      }
      if (Object.values(data).length > 0) {
        this.datas = data;
      } else {
        this.datas = this.datas;
      }
      let url = this.urls.query;
      url = _.isString(url)
        ? { url: url, method: "post" }
        : _.extend({ url: "", method: "post" }, url);

      let params = _.extend(
        {},
        {
          start: 0,
          length: this.finalPagerOptions.pageSize || 10,
          draw: 1,
          query: this.datas,
        },
        otherParams
      );

      if (this.beforeQuery) {
        this.beforeQuery(params);
      }
      let queryData =
        url.method.toLowerCase() === "get"
          ? { params: params }
          : { data: params };
      this.tableLoading = true;
      request({
        url: url.url,
        method: url.method,
        ...queryData,
      })
        .then(
          (result) => {
            if (this.afterQuery) {
              this.afterQuery(true, result);
            }
            this.data = _.extend(this.data, result);
            this.tableLoading = false;
          },
          (result) => {
            if (this.afterQuery) {
              this.afterQuery(false, result);
            }
            this.tableLoading = false;
            this.msgError("获取列表数据失败，请稍后重试");
          }
        )
        .catch((err) => {
          this.tableLoading = false;
        });
    },
    /**
     * 使用指定type的loader请求数据
     * @param {*} params 参数，需指定key和value
     * @param {*} type loader的类型
     */
    fetchData(params, type, preloader = true) {
      let loading;
      if (preloader) {
        loading = this.appLoading("数据加载中...");
      }
      return new Promise((rs, rj) => {
        this.getLoader(type)
          .query(params)
          .then(
            (values) => {
              this.bind(values);
              if (preloader) {
                loading.close();
              }
              rs();
            },
            (values) => {
              if (preloader) {
                loading.close();
              }
              this.msgError("请求失败，请稍候再试");
              console.error(values);
              rs();
            }
          );
      });
    },
    /**
     * 获取实体数据，如果参数没有指定实体的主键属性和值，则返回一个空的实体
     * @param {*} params 参数
     * @param {*} url 请求的url
     */
    getEntity(
      params = {
        pageAction: "create",
      },
      url = this.urls.entity
    ) {
      return new Promise((resolve, reject) => {
        if (!url) {
          this.msgError("没有指定获取实体的url");
          reject("没有指定获取实体的url");
        }

        this.onBeforeGetEntity(params);
        request({
          url: url,
          method: "post",
          data: params,
        })
          .then((r) => {
            this.onAfterGetEntity(r);
            if (r && !r.initMessage) {
              resolve(r);
            } else {
              reject(r.initMessage || "请求数据失败");
            }
          })
          .catch((e) => {
            reject(e);
          });
      });
    },

    onBeforeGetEntity(params) {},

    onAfterGetEntity(result) {},
    // 导出excel表格
    excelExport(postfix = ".xlsx") {
      let formMap = "{";
      this.getTableColumns().forEach((col) => {
        formMap += `"${col.field}":"${col.title}",`;
      });
      formMap = formMap.substring(0, formMap.length - 1) + "}";
      // 在controller上没有查找到search，使用data里面的search
      let search = this.viewModel.search;
      let queryParam = "";
      for (let o in search) {
        let queryKey = "query[" + o + "]";
        let queryValue = this.data.search[o];
        queryParam += `&${encodeURIComponent(queryKey)}=${encodeURIComponent(
          queryValue
        )}`;
      }
      let server = process.env.VUE_APP_SERVER;
      window.location.href = `${server}${
        this.urls.excelExport
      }?jsonStr=${encodeURIComponent(formMap)}&postfix=${encodeURIComponent(
        postfix
      )}${queryParam}`;
    },
    handleElPageSizeChange(pageSize) {
      let currentPage = this.data.startIndex;
      let params = {
        start: (currentPage - 1) * pageSize,
        length: pageSize,
      };
      this.refresh(params);
    },
    //页码改变时触发
    handleElPageChange(currentPage) {
      let pageSize = this.data.pageSize;
      let params = {
        start: (currentPage - 1) * pageSize,
        length: pageSize,
      };
      this.refresh(params);
    },
    handlePageChange({ currentPage, pageSize }) {
      let params = {
        start: (currentPage - 1) * pageSize,
        length: pageSize,
      };
      this.refresh(params);
    },
    seniorExport() {
      this.exportModalVisible = true;
      this.exportColumns = this.getTableColumns();
    },
    getTableColumns() {
      let columns = [];
      let defaults = this.$slots.default || [];
      _.each(defaults, (vnode) => {
        if (vnode.tag && vnode.tag.includes("qm-table-column")) {
          let colComp = vnode.componentInstance;
          let vxeTableCol = colComp.$refs["qmTableColumn"];
          let field = vxeTableCol.field;
          let title =
            vxeTableCol.title ||
            (colComp.$slots.default || [{ text: "" }])[0].text.trim();
          columns.push({ field: field, title: title });
        }
      });
      return columns;
    },
    // 列表中删除的方法
    // getCheckboxRecords : vxe方法 ：用于 type=checkbox，获取当前已选中的行数据（当前列表，如果 isFull=true 则获取全表已选中的数据）
    deleteSelected() {
      let selectRecords = this.$refs["xTable"].getCheckboxRecords()
      if (this.removeFunc) {
        return this.removeFunc(selectRecords);
      }
      let postModels = [];
      if (selectRecords.length === 0) {
        this.msgError("请至少选中一项");
        return;
      }
      selectRecords.forEach((item) => {
        let postModel = this.getPrimaryKey(this.keyProp, item);
        if (!_.isEmpty(postModel)) {
          postModels.push(postModel);
        }
      });
      let url = this.isRemoteList
        ? this.urls.remove || this.urls.delete
        : this.urls.delete || this.urls.delete;
      const lastPageDeleteRefreshParams = this.getLastPageDeleteRefreshParams(
        postModels.length
      );
      this.conremove(postModels, url)
        .then(() => {
          this.refresh(lastPageDeleteRefreshParams);
        })
        .catch(() => {});
    },
    getLastPageDeleteRefreshParams(removeCount) {
      let params = {};
      const { recordsTotal, startIndex, pageSize } = this.data;
      const condition =
        recordsTotal - removeCount <= (startIndex - 1) * pageSize &&
        recordsTotal != 0;
      if (condition) {
        params = {
          start: (startIndex - 2) * pageSize,
          length: pageSize,
        };
      }
      return params;
    },
    // 处理咱们的一个网络请求
    buildContext() {
      let models = new BaseModel();
      if (this.urls.query) {
        Util.each(Util.buildArray(this.urls.query), (t, i) => {
          models = Util.extend(models, new ListModel(i));
        });
      }
      this.context = models;
      this.context.pageLoading = false;
      this.onBuildContext(models);
    },
    //#region 删除
    onBeforeRemove(postModel) {
      return true;
    },
    onAfterRemove(isSuccess, result) {},
    afterRemove(isSuccess, result) {
      this.$message({
        showClose: true,
        message:
          result.message ||
          (isSuccess ? this.res.deleteSuccess : this.res.deleteError),
        type: isSuccess ? "success" : "error",
        onClose: ($message) => {
          this.onAfterRemove(isSuccess, result);
        },
      });
    },
    onBuildContext(models) {
      //overwrite
    },
    // 原本是controller控制器里面的remove事件
    conremove(
      postModel = this.context.primaryKey,
      url = this.urls.delete || this.urls.remove
    ) {
      return new Promise((resolve, reject) => {
        if (postModel == undefined || url == undefined) {
          this.afterRemove(false, {
            message: "PostModel或者URL不可为undefined",
          });
          reject();
        } else {
          if (this.onBeforeRemove(postModel)) {
            this.$confirm("确定删除嘛？", "提示", {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning",
            })
              .then(() => {
                let loading = this.appLoading("正在删除...");
                postModel = Util.isArray(postModel) ? postModel : [postModel];

                request({
                  url: url,
                  method: "post",
                  data: {
                    delete: JSON.stringify(postModel),
                  },
                })
                  .then((r) => {
                    this.afterRemove(r.success, r);
                    loading.close();
                    resolve(r);
                  })
                  .catch((e) => {
                    this.afterRemove(false, e);
                    loading.close();
                    reject(e);
                  });
              })
              .catch(() => {
                reject();
              });
          }
        }
      });
    },
    // 删除事件
    remove(row) {
      if (this.removeFunc) {
        return this.removeFunc([row]);
      }
      let postModel = this.getPrimaryKey(this.keyProp, row);
      let url = this.isRemoteList
        ? this.urls.remove || this.urls.delete
        : this.urls.delete;
      const lastPageDeleteRefreshParams =
        this.getLastPageDeleteRefreshParams(1);
      this.conremove(postModel, url)
        .then(() => {
          this.refresh(lastPageDeleteRefreshParams);
        })
        .catch(() => {});
    },
    // 左上角新增事件
    addNew() {
      this.$emit('addNew')
        // 以下为之前方法的源代码
      // if (this.addFunc) {
      //   return this.addFunc();
      // }
      // let url = this.isRemoteList
      //   ? this.urls.entity
      //   : this.urls.entity || this.urls.entity;
      // if (this.beforeGetEntity) {
      //   this.beforeGetEntity({}, {}, "create");
      // }
      // this.formModalVisible = true;
      // this.formModalLoading = true;
      // this.getEntity(undefined, url)
      //   .then((vm) => {
      //     this.viewModel = vm;
      //     this.primaryKey = {};
      //     this.pageAction = "create";
      //     this.formPath = this.computePage("create");
      //     this.formModalLoading = false;
      //     this.$nextTick(() => {
      //       this.formDisabled = false;
      //     });
      //   })
      //   .catch((e) => {
      //     this.msgError(e || "请求数据失败，请稍后再试");
      //   });
    },
    // 查看事件
    viewInfo(row) {
      this.$emit('viewInfo',row)
        // 以下为之前方法的源代码
      // if (this.viewFunc) {
      //   return this.viewFunc(row);
      // }
      // let params = this.getPrimaryKey(this.keyProp, row);
      // params["pageAction"] = "view";
      // let url = this.isRemoteList ? this.urls.entity : this.urls.entity;
      // if (this.beforeGetEntity) {
      //   this.beforeGetEntity(params, row, "view");
      // }
      // this.formModalVisible = true;
      // this.formModalLoading = true;
      // this.getEntity(params, url)
      //   .then((vm) => {
      //     this.viewModel = vm;
      //     this.primaryKey = {};
      //     this.pageAction = "view";
      //     this.formPath = this.computePage("view");
      //     this.formModalLoading = false;
      //     this.$nextTick(() => {
      //       this.formDisabled = true;
      //     });
      //   })
      //   .catch((e) => {
      //     this.msgError(e || "请求数据失败，请稍后再试");
      //   });
    },
    // 编辑事件
    showEditModal(row) {
      this.$emit('showEditModal',row)
        // 以下为之前方法的源代码
      // if (this.editFunc) {
      //   return this.editFunc(row);
      // }
      // let params = this.getPrimaryKey(this.keyProp, row);
      // params["pageAction"] = "edit";
      // let url = this.isRemoteList
      //   ? this.urls.entity
      //   : this.urls.entity || this.urls.entity;
      // if (this.beforeGetEntity) {
      //   this.beforeGetEntity(params, row, "edit");
      // }
      // this.formModalVisible = true;
      // this.formModalLoading = true;
      // this.getEntity(params, url)
      //   .then((vm) => {
      //     this.viewModel = vm;
      //     let primaryKey = this.getPrimaryKey(this.keyProp, row);
      //     this.primaryKey = primaryKey;
      //     this.pageAction = "edit";
      //     this.formPath = this.computePage("edit");
      //     this.formModalLoading = false;
      //     this.$nextTick(() => {
      //       this.formDisabled = false;
      //     });
      //   })
      //   .catch((e) => {
      //     this.msgError(e || "请求数据失败，请稍后再试");
      //   });
    },
    //#region 禁止重写方法
    polyfill() {
      this.onInit();
      // Services.setInstance("controller", this.vm.$route.path, this);
    },
    onInit() {
      //overwrite
    },
    //#region 加载数据，需要返回Promise，Promise的then方法会返回一个新的Promise实例
    getViewModel(conditions, preloader = false) {
      this.context.pageLoading = true;
      let loading;
      if (preloader) {
        loading = this.appLoading("数据加载中...");
      }
      return new Promise((resolve, reject) => {
        new LoaderProxy(this, conditions).load(resolve, reject, preloader);
      })
        .then(() => {
          this.context.pageLoading = false;
          if (preloader) {
            loading.close();
          }
        })
        .catch(() => {
          this.context.pageLoading = false;
          if (preloader) {
            loading.close();
          }
        });
    },
    // framework(){
    //   return Vue.prototype.$framework
    // },
    params() {
      let q = this.vm.$route.query;
      let ps = this.vm.$route.params;
      let attrs = this.vm.$attrs;
      //如果是模态窗口，不取值当前路由参数
      if (!this.$util.isEmpty(attrs) && attrs._modal) {
        if (Object.keys(attrs).length > 1) {
          return this.$util.extend({}, attrs);
        }
      } else {
        if (
          !this.$util.isEmpty(q) ||
          !this.$util.isEmpty(ps) ||
          !this.$util.isEmpty(attrs)
        ) {
          return this.$util.extend({}, q || {}, ps || {}, attrs || {});
        }
      }

      let queryString = qs.parse(window.location.search, {
        ignoreQueryPrefix: true,
      });
      if (!this.$util.isEmpty(queryString)) {
        return queryString;
      }
      return {};
    },
    $params() {
      return this.params();
    },
  },
  created() {
    this.polyfill();
    let loading = this.showLoading;
    if ((this.$attrs || {}).showAppLoading === false) {
      loading = false;
    }
    this.getViewModel({}, loading).then(() => {
      if (this.autoLoadDone) {
        if (this.pageLoadDone) {
          this.pageLoadDone();
        } else {
          this.$emit("loaded");
        }
      }
    });
    this.buildContext();
    if (!this.context || Util.isEmpty(this.context)) {
      this.buildContext();
    }
    if (!this.isRemoteList) {
      return;
    }
    this.vm = this;
    this.util = Util;
    this.fetchListData();
  },
  mounted() {
    loadAutoTriggerGuide(this.$route.path);
  },
  activated() {
    if (this.autoMountManualTriggerGuide) {
      mountManualTriggerGuide(this.$route.path);
    }
  },
  beforeRouteEnter(to, form, next) {
    next();
  },
  beforeRouteUpdate(to, form, next) {
    next();
  },
};
</script>

<style scoped lang="scss">
.qm-table {
  margin: 12px 0;

  .qm-table-vxe-table {
    margin: 6px 0;

    .qm-table-menu-link {
      padding-right: 8px;
    }
  }
  .qm-table-form-modal {
    .qm-table-form {
      max-height: calc(100vh - 200px);
      margin: 8px 16px 8px 8px;
      .qm-table-form-toolbar {
        text-align: right;
      }
    }
    .qm-table-form-row {
      text-align: right;
      // margin: 12px 0;
    }
  }
  .qm-table-el-pager {
    margin-top: 16px;
    font-weight: normal;
  }
}
</style>

